#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <QtGlobal>

#include "eeecontrol.h"

#define EC_IDX_ADDRH 0x381
#define EC_IDX_ADDRL 0x382
#define EC_IDX_DATA 0x383
#define HIGH_BYTE(x) ((x & 0xff00) >> 8)
#define LOW_BYTE(x) (x & 0x00ff)

void outb(unsigned char value, unsigned short port)
{
    int fio = open("/dev/port", O_RDWR);
    lseek(fio, port, SEEK_SET);
    write(fio, &value, 1);
    close(fio);
}

unsigned char inb(unsigned short port)
{
    unsigned char c;

    int fio = open("/dev/port", O_RDWR);
    lseek(fio, port, SEEK_SET);
    read(fio, &c, 1);
    close(fio);

    return c;
}

EeeControl* EeeControl::instance = 0;

EeeControl* EeeControl::getInstance()
{
    if (!instance) {
        instance = new EeeControl();
    }
    return instance;
}

EeeControl::EeeControl()
{
    int fio = open("/dev/port", O_RDWR);
    if (-1 == fio) {
        qWarning(strerror(errno));
        portsAvailable = false;
    } else {
        close(fio);
        portsAvailable = true;
    }
}

EeeControl::FanMode EeeControl::fanMode()
{
    unsigned char c = getEcRegisterValue(0xF4D3);
    if (c & 0x02) {
        return FanModeManual;
    } else {
        return FanModeAuto;
    }
    //return FanModeUnknown;
}

bool EeeControl::setFanMode(EeeControl::FanMode mode)
{
    unsigned char c = getEcRegisterValue(0xF4D3);
    if (FanModeManual == mode) {
        setEcRegisterValue(0xF4D3, c | 0x02);
    } else {
        setEcRegisterValue(0xF4D3, c & ~0x02);
    }
    return true;
}

unsigned char EeeControl::fanSpeedPercent()
{
    return getEcRegisterValue(0xF463);
}

bool EeeControl::setFanSpeedPercent(unsigned char value)
{
    return setEcRegisterValue(0xF463, value > 100 ? 100 : value);
}

int EeeControl::fanSpeedRpm()
{
    unsigned char highByte;
    unsigned char lowByte;

    highByte = getEcRegisterValue(0xF466);
    lowByte = getEcRegisterValue(0xF467);

    return (highByte << 8) | (lowByte);
}

int EeeControl::temperature()
{
    return getEcRegisterValue(0xF451);
}

bool EeeControl::isPortsAvailable()
{
    return portsAvailable;
}


unsigned char EeeControl::getEcRegisterValue(unsigned short address)
{
    // put address of the register into I/O ports EC_IDX_ADDRH, EC_IDX_ADDRL
    outb(HIGH_BYTE(address), EC_IDX_ADDRH);
    outb(LOW_BYTE(address), EC_IDX_ADDRL);

    unsigned char data;
    data = inb(EC_IDX_DATA);
    return data;
}

bool EeeControl::setEcRegisterValue(unsigned short address, unsigned char data)
{
    // put address of the register into I/O ports EC_IDX_ADDRH, EC_IDX_ADDRL
    outb(HIGH_BYTE(address), EC_IDX_ADDRH);
    outb(LOW_BYTE(address), EC_IDX_ADDRL);
    
    outb(data, EC_IDX_DATA);
    return true;
}
